package service

import (
	"encoding/json"
	"errors"
	"fmt"
	"github.com/dchest/captcha"
	"haiqiu-go-admin/config"
	"haiqiu-go-admin/dao"
	"haiqiu-go-admin/entity"
	"haiqiu-go-admin/entity/dto"
	"haiqiu-go-admin/entity/vo"
	"haiqiu-go-admin/result"
	"haiqiu-go-admin/utils"
	"io"
	"io/fs"
	"log"
	"net/http"
	"os"
	"path"
	"strconv"
	"strings"
	"time"
)

func Login(loginDto *dto.LoginDto) (any, error) {
	if loginDto == nil {
		return nil, errors.New("参数错误")
	}
	if loginDto.Username == "" {
		return nil, errors.New("用户名不能为空")
	}
	if loginDto.Password == "" {
		return nil, errors.New("密码不能为空")
	}
	//判断是否需要验证码
	err := checkCaptcha(loginDto)
	if err != nil {
		return nil, err
	}
	user, err := dao.SelectUserByUserName(loginDto.Username)
	if err != nil {
		return nil, errors.New("用户不存在")
	}
	if !utils.PasswordVerify(loginDto.Password, user.Password) {
		return nil, errors.New("密码错误")
	}
	token, _ := utils.Token{}.GenerateToken(user.Id, user.Username)
	//生成token返回
	mapData := make(map[string]interface{})
	mapData["token"] = token
	return mapData, nil
}

func UserById(userId int64) (*vo.UserVo, error) {
	var userVo vo.UserVo
	user, err := dao.UserById(userId)
	//数据安全，默认设置用户密码为空
	user.Password = ""
	if err != nil {
		log.Println("查询用户出错：" + err.Error())
		return nil, err
	}
	marshal, err := json.Marshal(user)

	err = json.Unmarshal(marshal, &userVo)
	if user.DeptId != nil {
		dept, _ := dao.DeptById(*user.DeptId)
		userVo.Dept = dept
	}

	roles, err := dao.RoleByUserId(user.Id)
	if err != nil {
		log.Println(err.Error())
		return nil, err
	}
	userVo.RoleList = roles

	positions, err := dao.PositionByUserId(user.Id)
	if err != nil {
		log.Println(err.Error())
		return nil, err
	}
	userVo.PositionList = positions
	return &userVo, nil
}

// 检测验证码
func checkCaptcha(loginDto *dto.LoginDto) error {
	config, err := ConfigSelectByPrimaryKey(1)
	if err != nil {
		return errors.New("系统配置错误")
	}
	if config.Captcha {
		if captcha.VerifyString(loginDto.Key, loginDto.Captcha) {
			log.Println("验证码校验成功")
		} else {
			return errors.New("验证码错误")
		}
	}
	return nil
}

// UserPage 用户分页
func UserPage(w http.ResponseWriter, r *http.Request) (any, error) {
	formatJson, err := utils.GetBodyFormatJson(w, r)
	if err != nil {
		return nil, errors.New(result.ParamsErr)
	}
	var page = dto.UserQueryDto{}
	err = json.Unmarshal(formatJson, &page)
	if err != nil {
		log.Println(err)
		return nil, err
	}
	count, err := dao.UserPageCount(page)
	if err != nil {
		return nil, err
	}
	var pageData vo.PageData
	list, err := dao.UserPageList(page)
	pageData.Data = list
	pageData.Total = count
	pageData.PageIndex = page.PageIndex
	pageData.PageSize = page.PageSize
	if err != nil {
		return nil, err
	}
	return pageData, nil
}

// UserAdd 添加用户
func UserAdd(w http.ResponseWriter, r *http.Request) (any, error) {
	formatJson, err := utils.GetBodyFormatJson(w, r)
	if err != nil {
		return nil, err
	}
	var sysUser = entity.SysUser{}
	err = json.Unmarshal(formatJson, &sysUser)
	var userDto = dto.UserDto{}
	err = json.Unmarshal(formatJson, &userDto)
	if err != nil {
		return nil, err
	}
	var nowTime = time.Now()
	var del = false
	sysUser.Del = &del
	sysUser.CreateTime = &nowTime
	sysUser.UpdateTime = &nowTime
	passwordHash, err := utils.PasswordEncode(sysUser.Password)
	if err != nil {
		return nil, err
	}
	sysUser.Password = passwordHash
	lastInsertId, err := dao.UserAdd(&sysUser)
	if err != nil {
		return nil, err
	}
	userDto.Id = lastInsertId
	err = addUserAssociation(&userDto)
	if err != nil {
		panic(err)
		return nil, err
	}
	return lastInsertId, nil
}

// 添加用户关联关系
func addUserAssociation(userDto *dto.UserDto) error {
	if len(userDto.RoleIds) != 0 {
		err := dao.DeleteUserByRole(userDto.Id)
		if err != nil {
			return err
		}
		_, err = dao.AddUserByRole(userDto.Id, userDto.RoleIds)
		if err != nil {
			return err
		}
	}
	if len(userDto.PositionIds) != 0 {
		err := dao.DeleteUserByPosition(userDto.Id)
		if err != nil {
			return err
		}
		err = dao.AddUserByPosition(userDto.Id, userDto.PositionIds)
		if err != nil {
			return err
		}
	}
	return nil
}

func UserUpdate(w http.ResponseWriter, r *http.Request) (any, error) {
	formatJson, err := utils.GetBodyFormatJson(w, r)
	if err != nil {
		return nil, err
	}
	var sysUser = entity.SysUser{}
	err = json.Unmarshal(formatJson, &sysUser)
	var userDto = dto.UserDto{}
	err = json.Unmarshal(formatJson, &userDto)
	if err != nil {
		return nil, err
	}
	var nowTime = time.Now()
	var del = false
	sysUser.Del = &del
	sysUser.UpdateTime = &nowTime
	lastInsertId, err := dao.UserUpdate(&sysUser)
	if err != nil {
		return nil, err
	}
	err = addUserAssociation(&userDto)
	if err != nil {
		panic(err)
		return nil, err
	}
	return lastInsertId, nil
}

func UserDeleteBatch(w http.ResponseWriter, r *http.Request) (any, error) {
	formatJson, err := utils.GetBodyFormatJson(w, r)
	if err != nil {
		return nil, err
	}
	var ids []int64
	err = json.Unmarshal(formatJson, &ids)
	if err != nil {
		return nil, err
	}

	add, err := dao.UserDeleteBatch(ids)
	if err != nil {
		return nil, err
	}
	return add, nil
}

func UserList(w http.ResponseWriter, r *http.Request) (*[]entity.SysUser, error) {
	userList, err := dao.UserList()
	if err != nil {
		log.Println(err.Error())
		return nil, err
	}
	return userList, nil
}

func AuthRole(w http.ResponseWriter, r *http.Request) (any, error) {
	formatJson := utils.GetParamsFormatJson(w, r)
	if formatJson == nil {
		return nil, errors.New(result.ParamsErr)
	}
	userId, err := strconv.ParseInt(formatJson["userId"][0], 10, 64)
	if err != nil {
		log.Println(err.Error())
		panic(err)
	}
	roleIdsStr := formatJson["roleIds"][0]
	roleIdsStrArr := strings.Split(roleIdsStr, ",")
	roleIds := make([]int64, 0)
	for _, roleId := range roleIdsStrArr {
		i, err := strconv.ParseInt(roleId, 10, 64)
		if err != nil {
			log.Println(err.Error())
			panic(err)
		}
		roleIds = append(roleIds, i)
	}
	if err != nil {
		log.Println(err.Error())
		panic(err)
	}
	_, err = dao.AddUserByRole(userId, roleIds)
	if err != nil {
		return nil, err
	}
	return nil, nil
}

func Active(w http.ResponseWriter, r *http.Request) (any, error) {
	formatJson, err := utils.GetBodyFormatJson(w, r)
	if err != nil {
		log.Println(err.Error())
		panic(err)
		return nil, err
	}
	var sysUser entity.SysUser
	err = json.Unmarshal(formatJson, &sysUser)
	if err != nil {
		log.Println(err.Error())
		panic(err)
		return nil, err
	}
	rowsAffected, err := dao.ActiveUserById(sysUser.Id, sysUser.Active)
	return rowsAffected, err
}

func ResetPwd(w http.ResponseWriter, r *http.Request) (any, error) {
	formatJson, err := utils.GetBodyFormatJson(w, r)
	if err != nil {
		log.Println(err.Error())
		panic(err)
		return nil, err
	}
	mapData := make(map[string]any)
	err = json.Unmarshal(formatJson, &mapData)
	if err != nil {
		log.Println(err.Error())
		panic(err)
		return nil, err
	}
	userIdStr := mapData["userId"]
	newPassword := mapData["newPassword"]
	userId, err := strconv.ParseInt(fmt.Sprintf("%v", userIdStr), 10, 64)
	if err != nil {
		log.Println(err.Error())
		panic(err)
		return nil, err
	}
	encode, err := utils.PasswordEncode(fmt.Sprintf("%v", newPassword))
	if err != nil {
		log.Println(err.Error())
		panic(err)
		return nil, err
	}
	rowsAffected, err := dao.ResetPwd(userId, encode)
	return rowsAffected, err
}

func AvatarUpload(w http.ResponseWriter, r *http.Request) (any, error) {
	file, header, err := r.FormFile("avatarfile")
	if err != nil {
		return nil, err
	}
	defer file.Close()

	fileNameAll := path.Base(header.Filename)
	fileSuffix := path.Ext(fileNameAll)
	//filePrefix := fileNameAll[0 : len(fileNameAll)-len(fileSuffix)]
	avatar := "/avatar/"
	newFileName := fmt.Sprintf("%d%v", time.Now().UnixMilli(), fileSuffix)
	filePath := fmt.Sprintf("%v", config.AppConfig.Http.Parent) + avatar + newFileName
	err = os.MkdirAll(fmt.Sprintf("%v", config.AppConfig.Http.Parent)+avatar, fs.ModeDir)
	if err != nil {
		return nil, err
	}
	dst, err := os.Create(filePath)
	if err != nil {
		return nil, err
	}
	defer dst.Close()
	_, err = io.Copy(dst, file)
	if err != nil {
		return nil, err
	}
	var url = fmt.Sprintf("%v", config.AppConfig.Http.Server)
	suffix := fmt.Sprintf("%v", config.AppConfig.Http.Virtual) + avatar +
		newFileName
	replaceAll := strings.ReplaceAll(suffix, "//", "/")
	return url + replaceAll, nil
}
